# -*- coding: utf-8 -*-
##############################################################################
#
#    OpenERP, Open Source Management Solution
#    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp.osv import fields, osv
from openerp.tools.translate import _
from openerp import netsvc
from openerp.tools.float_utils import float_compare
import openerp.addons.decimal_precision as dp
from openerp import api
from openerp import workflow
from samba.dcerpc.samr import Ids

class account_analytic_account(osv.osv):

    _inherit = 'account.analytic.account'
    
    def _get_dept1_alias(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        alias_dept1 = ''
        
        for rec in self.browse(cr, uid, ids, context=context):
            if rec.company_id.dept1_alias:
                alias_dept1 = rec.company_id.dept1_alias
            else:
                alias_dept1 = 'Department1'
            result[rec.id] = alias_dept1
        return result
    
    def _get_dept2_alias(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        alias_dept2 = ''
        
        for rec in self.browse(cr, uid, ids, context=context):
            if rec.company_id.dept2_alias:
                alias_dept2 = rec.company_id.dept2_alias
            else:
                alias_dept2 = 'Department2'
            result[rec.id] = alias_dept2
        return result
    
    def _get_dept3_alias(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        alias_dept3 = ''
        
        for rec in self.browse(cr, uid, ids, context=context):
            if rec.company_id.dept3_alias:
                alias_dept3 = rec.company_id.dept3_alias
            else:
                alias_dept3 = 'Department3'
            result[rec.id] = alias_dept3
        return result
    
    def get_parent_partner_id(self, partner_id):
        new_partner_id = False
        if partner_id.parent_id:
            new_partner_id = partner_id.parent_id
        if new_partner_id:
            new_partner_id = self.get_parent_partner_id(new_partner_id)
        else:
            new_partner_id = partner_id
        return new_partner_id

    def _get_real_partner(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        for rec in self.browse(cr, uid, ids, context=context):
            new_partner_id = self.get_parent_partner_id(rec.partner_id)
            result[rec.id] = new_partner_id.id
        return result
    
    def cust_quotation_print(self, cr, uid, ids, context=None):
        if context is None:
           context = {}
        data = self.read(cr, uid, ids)[0]
        self_browse = self.browse(cr, uid, ids)
        
        datas = {
            'ids': [data.get('id')],
            'model': 'account.analytic.account',
            'form': data
            }
        return {
            'type': 'ir.actions.report.xml',
            'report_name': 'batam_fast_module.ami_cust_quotation2',
            'datas': datas,
            'name': self_browse.code
            }
    
    def unlink(self, cr, uid, ids, context=None):

        raise osv.except_osv(
            _('Invalid Action!'),
            _('you can not delete the Contract except in Cancel.')
        )

        return super(account_analytic_account, self).unlink(cr, uid, ids, context=context)
    
    def get_qry_hours(self, cr, uid, ids, department, type, context=None):
        cr.execute("SELECT aaa.id as analytic_id, COALESCE(SUM(ptw.hours),0) FROM project_task_work ptw " + \
                   "left join project_task pt on ptw.task_id = pt.id " + \
                   "left join project_project pp on pt.project_id = pp.id " + \
                   "left join account_analytic_account aaa on pp.analytic_account_id = aaa.id " + \
                    "WHERE aaa.id IN %s and ptw.department = %s and ptw.type = %s GROUP BY analytic_id", \
                    (tuple(ids), department, type))
        return dict(cr.fetchall())

    def _hours_get(self, cr, uid, ids, field_names, args, context=None):
        """
           This function returns the residual amount on a receivable or payable account.move.line.
           By default, it returns an amount in the currency of this journal entry (maybe different
           of the company currency), but if you pass 'residual_in_company_currency' = True in the
           context then the returned amount will be in company currency.
        """
        res = {}
        if context is None:
            context = {}
        #shipyard
        sy_actual_hours = self.get_qry_hours(cr,uid,ids,'shipyard','normal')
        sy_actual_ot_hours = self.get_qry_hours(cr,uid,ids,'shipyard','ot')
        #mechanical
        mech_actual_hours = self.get_qry_hours(cr,uid,ids,'mechanical','normal')
        mech_actual_ot_hours = self.get_qry_hours(cr,uid,ids,'mechanical','ot')
        #electrical
        elec_actual_hours = self.get_qry_hours(cr,uid,ids,'electrical','normal')
        elec_actual_ot_hours = self.get_qry_hours(cr,uid,ids,'electrical','ot')
        #Welding & Fabrication
        weld_actual_hours = self.get_qry_hours(cr,uid,ids,'welding_fabrication','normal')
        weld_actual_ot_hours = self.get_qry_hours(cr,uid,ids,'welding_fabrication','ot')
        #Interior
        int_actual_hours = self.get_qry_hours(cr,uid,ids,'interior','normal')
        int_actual_ot_hours = self.get_qry_hours(cr,uid,ids,'interior','ot')
        #Design
        desg_actual_hours = self.get_qry_hours(cr,uid,ids,'design','normal')
        desg_actual_ot_hours = self.get_qry_hours(cr,uid,ids,'design','ot')
        #Other Dept1
        dept1_actual_hours = self.get_qry_hours(cr,uid,ids,'other_dept1','normal')
        dept1_actual_ot_hours = self.get_qry_hours(cr,uid,ids,'other_dept1','ot')
        #Other Dept2
        dept2_actual_hours = self.get_qry_hours(cr,uid,ids,'other_dept2','normal')
        dept2_actual_ot_hours = self.get_qry_hours(cr,uid,ids,'other_dept2','ot')
        #Other Dept3
        dept3_actual_hours = self.get_qry_hours(cr,uid,ids,'other_dept3','normal')
        dept3_actual_ot_hours = self.get_qry_hours(cr,uid,ids,'other_dept3','ot')
        
        for anlytic in self.browse(cr, uid, ids, context=context):
            res[anlytic.id] = {
                'sy_actual_normal_hours': sy_actual_hours.get(anlytic.id, 0.0),
                'sy_actual_ot_hours': sy_actual_ot_hours.get(anlytic.id, 0.0),
                'mech_actual_normal_hours': mech_actual_hours.get(anlytic.id, 0.0),
                'mech_actual_ot_hours': mech_actual_ot_hours.get(anlytic.id, 0.0),
                'elec_actual_normal_hours': elec_actual_hours.get(anlytic.id, 0.0),
                'elec_actual_ot_hours': elec_actual_ot_hours.get(anlytic.id, 0.0),
                'weld_actual_normal_hours': weld_actual_hours.get(anlytic.id, 0.0),
                'weld_actual_ot_hours': weld_actual_ot_hours.get(anlytic.id, 0.0),
                'int_actual_normal_hours': int_actual_hours.get(anlytic.id, 0.0),
                'int_actual_ot_hours': int_actual_ot_hours.get(anlytic.id, 0.0),
                'desg_actual_normal_hours':desg_actual_hours.get(anlytic.id, 0.0),
                'desg_actual_ot_hours': desg_actual_ot_hours.get(anlytic.id, 0.0),
                'dept1_actual_normal_hours':dept1_actual_hours.get(anlytic.id, 0.0),
                'dept1_actual_ot_hours': dept1_actual_ot_hours.get(anlytic.id, 0.0),
                'dept2_actual_normal_hours':dept2_actual_hours.get(anlytic.id, 0.0),
                'dept2_actual_ot_hours': dept2_actual_ot_hours.get(anlytic.id, 0.0),
                'dept3_actual_normal_hours':dept3_actual_hours.get(anlytic.id, 0.0),
                'dept3_actual_ot_hours': dept3_actual_ot_hours.get(anlytic.id, 0.0),
            }
            
        return res
    
    def get_qry_inv_qty(self, cr, uid, ids, analytic_id, department, ot_flag, context=None):
        cr.execute("select aaa.id as analytic_id, ail.quantity as qty from account_invoice_line ail " + \
                   "left join account_invoice ai on ail.invoice_id = ai.id " + \
                   "left join account_analytic_account aaa on ai.analytic_contract_id = aaa.id " + \
                   "where ail.labour_flag = True and ai.state <> 'cancel' and aaa.id = %s and ail.type = %s and ail.ot_flag = %s limit 1 ", (analytic_id.id, department, ot_flag,))
        qry = cr.dictfetchall()
        qty = 0
        data = {}
        if qry:
            for t in qry:
                qty = t['qty']
        return qty
 
    def _inv_hours_get(self, cr, uid, ids, field_names, args, context=None):

        res = {}
        if context is None:
            context = {}
            
        f = bool(0)
        t = bool(1)
        
        for anlytic in self.browse(cr, uid, ids, context=context):
            res[anlytic.id] = {
                'sy_normal_invoice_qty': self.get_qry_inv_qty(cr,uid,ids,anlytic,'shipyard',f),
                'sy_ot_invoice_qty': self.get_qry_inv_qty(cr,uid,ids,anlytic,'shipyard',t),
                'mech_normal_invoice_qty': self.get_qry_inv_qty(cr,uid,ids,anlytic,'mechanical',f),
                'mech_ot_invoice_qty': self.get_qry_inv_qty(cr,uid,ids,anlytic,'mechanical',t),
                'elec_normal_invoice_qty': self.get_qry_inv_qty(cr,uid,ids,anlytic,'electrical',f),
                'elec_ot_invoice_qty': self.get_qry_inv_qty(cr,uid,ids,anlytic,'electrical',t),
                'weld_normal_invoice_qty': self.get_qry_inv_qty(cr,uid,ids,anlytic,'welding_fabrication',f),
                'weld_ot_invoice_qty': self.get_qry_inv_qty(cr,uid,ids,anlytic,'welding_fabrication',t),
                'int_normal_invoice_qty': self.get_qry_inv_qty(cr,uid,ids,anlytic,'interior',f),
                'int_ot_invoice_qty': self.get_qry_inv_qty(cr,uid,ids,anlytic,'interior',t),
                'desg_normal_invoice_qty': self.get_qry_inv_qty(cr,uid,ids,anlytic,'design',f),
                'desg_ot_invoice_qty': self.get_qry_inv_qty(cr,uid,ids,anlytic,'design',t),
                'dept1_normal_invoice_qty': self.get_qry_inv_qty(cr,uid,ids,anlytic,'other_dept1',f),
                'dept1_ot_invoice_qty': self.get_qry_inv_qty(cr,uid,ids,anlytic,'other_dept1',t),
                'dept2_normal_invoice_qty': self.get_qry_inv_qty(cr,uid,ids,anlytic,'other_dept2',f),
                'dept2_ot_invoice_qty': self.get_qry_inv_qty(cr,uid,ids,anlytic,'other_dept2',t),
                'dept3_normal_invoice_qty': self.get_qry_inv_qty(cr,uid,ids,anlytic,'other_dept3',f),
                'dept3_ot_invoice_qty': self.get_qry_inv_qty(cr,uid,ids,anlytic,'other_dept3',t),
            }
  
        return res
    
    def get_error(self, cr, uid, type, data, err_mess, context=None):
        if type in data:
            product_ids = []
            for lines in data[type]:
                if lines[2]['product_id'] in product_ids:
                    product_name = self.pool.get('product.product').browse(cr, uid, product_id, context=None).name
                    raise osv.except_osv(_('Error!'), _('cannot insert same Product for one %s department! (%s)')%(err_mess, product_name))
                else:
                    product_ids.append(lines[2]['product_id'])
        return True
    
    def create(self, cr, uid, data, context=None):

        self.get_error(cr,uid,'shipyard_line_ids',data, 'Shipyard')
        self.get_error(cr,uid,'mechanical_line_ids',data, 'Mechanical')
        self.get_error(cr,uid,'electrical_line_ids',data, 'Electrical')
        self.get_error(cr,uid,'welding_line_ids',data, 'Welding & Fabrication')
        self.get_error(cr,uid,'interior_line_ids',data, 'Interior')
        self.get_error(cr,uid,'design_line_ids',data, 'Design')
        self.get_error(cr,uid,'department1_line_ids',data, 'Other Dept1')
        self.get_error(cr,uid,'department2_line_ids',data, 'Other Dept2')
        self.get_error(cr,uid,'department3_line_ids',data, 'Other Dept3')
        
        return super(account_analytic_account, self).create(cr, uid, data, context)

    def get_error_write(self, cr, uid, ids, type, data, err_mess, context=None):
#2 = Delete
#4 = no change
#0 = add
#1 = edit
        product_uom_obj = self.pool.get('product.uom')
        if type in data:
            product_ids = []
            for lines in data[type]:
                if lines[0] == 2:
                    analytic_line = self.pool.get('analytic.quotation.line').browse(cr, uid, lines[1], context=None)
                    generated_qty = analytic_line.process_qty
                    if generated_qty > 0:
                        raise osv.except_osv(_('Error!'), _('cannot delete product which have Internal Move Qty %s for %s department! (%s)')%(generated_qty, err_mess, analytic_line.product_id.name))
                    continue
                if lines[0] == 4:
                    product_id = self.pool.get('analytic.quotation.line').browse(cr, uid, lines[1], context=None).product_id.id
                if lines[0] == 1:
                    analytic_line = self.pool.get('analytic.quotation.line').browse(cr, uid, lines[1], context=None)
                    generated_qty = analytic_line.process_qty
                    if 'product_id' in lines[2]:
                        if lines[2]['product_id'] != analytic_line.product_id.id:
                            if generated_qty > 0:
                                raise osv.except_osv(_('Error!'), _('cannot change to other product which have Internal Move Qty %s for %s department! ("%s" -> "%s")')%(generated_qty, err_mess, analytic_line.product_id.name, self.pool.get('product.product').browse(cr, uid, lines[2]['product_id'], context=None).name))   
                    product_id = ('product_id' in lines[2] and lines[2]['product_id']) or analytic_line.product_id.id
                    product_qty = ('product_qty' in lines[2] and lines[2]['product_qty']) or analytic_line.product_qty
                    product_uom = ('product_uom' in lines[2] and lines[2]['product_uom']) or analytic_line.product_uom.id
                    product_product_id = self.pool.get('product.product').browse(cr, uid, product_id, context=None)
                    default_uom = product_product_id.uom_id and product_product_id.uom_id.id
                    real_quantity = product_uom_obj._compute_qty(cr, uid, product_uom and product_uom, \
                                                     product_qty, default_uom)
                    if real_quantity < generated_qty:
                        raise osv.except_osv(_('Error!'), _('the quantity entered is below the Internal Move Qty(%s) for %s department! ("%s")')%(generated_qty, err_mess, analytic_line.product_id.name))
                if lines[0] == 0:
                    product_id = ('product_id' in lines[2] and lines[2]['product_id'])
                if product_id in product_ids:
                    product_name = self.pool.get('product.product').browse(cr, uid, product_id, context=None).name
                    raise osv.except_osv(_('Error!'), _('cannot insert same Product for one %s department! (%s)')%(err_mess, product_name)) 
                else:
                    product_ids.append(product_id)
        return True
    
    def get_error_write_srvc(self, cr, uid, ids, type, data, err_mess, context=None):
#2 = Delete
#4 = no change
#0 = add
#1 = edit
        if type in data:
            product_ids = []
            for lines in data[type]:
                if lines[0] == 2:
                    analytic_line = self.pool.get('analytic.service.quotation.line').browse(cr, uid, lines[1], context=None)
                    invoices_qty = analytic_line.invoices_service_qty
                    if invoices_qty > 0:
                        raise osv.except_osv(_('Error!'), _('cannot delete service product which have invoices qty %s for %s department! (%s)')%(invoices_qty, err_mess, analytic_line.product_id.name))
                    continue
                if lines[0] == 4:
                    continue
                if lines[0] == 1:
                    analytic_line = self.pool.get('analytic.service.quotation.line').browse(cr, uid, lines[1], context=None)
                    invoices_qty = analytic_line.invoices_service_qty
                    if 'product_id' in lines[2]:
                        if lines[2]['product_id'] != analytic_line.product_id.id:
                            if invoices_qty > 0:
                                raise osv.except_osv(_('Error!'), _('cannot change to other service product which have invoices qty %s for %s department! ("%s" -> "%s")')%(invoices_qty, err_mess, analytic_line.product_id.name, self.pool.get('product.product').browse(cr, uid, lines[2]['product_id'], context=None).name))   
                    product_qty = lines[2]['product_qty'] if 'product_qty' in lines[2] else analytic_line.product_qty
                    if  product_qty < invoices_qty:
                        raise osv.except_osv(_('Error!'), _('The quantity entered is below the invoices qty(%s) for %s department! ("%s")')%(invoices_qty, err_mess, analytic_line.product_id.name))
                if lines[0] == 0:
                    continue
        return True
    
    def get_error_write_cond1(self, cr, uid, ids, estimated_qty, actual_qty, type, dept, context=None):
        # 1st condition estimated hour(s) input must be greater than actual hour(s)
        if estimated_qty < actual_qty:
            raise osv.except_osv(_('Invalid Action!'), _('Please check carefully in %s dept, estimated %s %s hour(s) but actual %s %s hour(s)!') % (dept, type, estimated_qty, type, actual_qty,))
        
        return True
    
    def get_error_write_cond2(self, cr, uid, ids, invoices_qty, actual_qty, type, dept, context=None):
        # 2nd condition invoices hour(s) input must not be greater than actual hour(s)
        if invoices_qty > actual_qty:
            raise osv.except_osv(_('Invalid Action!'), _('Please check carefully in %s dept, invoices %s %s hour(s) but actual %s %s hour(s)!') % (dept, type, invoices_qty, type, actual_qty,))
        
        return True
    
    def get_error_write_cond3(self, cr, uid, ids, estimated_qty, invoices_qty, type, dept, context=None):
        # 3rd condition for non actual billing, estimated hour(s) input must be greater than invoices hour(s)
        if estimated_qty < invoices_qty:
            raise osv.except_osv(_('Invalid Action!'), _('Please check carefully in %s dept, estimated %s %s hour(s) but invoices %s %s hour(s)!') % (dept, type, estimated_qty, type, invoices_qty,))
        
        return True
    
    def write(self, cr, uid, ids, vals, context=None):
        
        analytic_account = self.pool.get('account.analytic.account').browse(cr, uid, ids[0], context=None)
        
        sy_normal_qty = vals['sy_normal_qty'] if 'sy_normal_qty' in vals else analytic_account.sy_normal_qty
        sy_ot_qty = vals['sy_ot_qty'] if 'sy_ot_qty' in vals else analytic_account.sy_ot_qty
        mech_normal_qty = vals['mech_normal_qty'] if 'mech_normal_qty' in vals else analytic_account.mech_normal_qty
        mech_ot_qty = vals['mech_ot_qty'] if 'mech_ot_qty' in vals else analytic_account.mech_ot_qty
        elec_normal_qty = vals['elec_normal_qty'] if 'elec_normal_qty' in vals else analytic_account.elec_normal_qty
        elec_ot_qty = vals['elec_normal_qty'] if 'elec_ot_qty' in vals else analytic_account.elec_ot_qty
        weld_normal_qty = vals['elec_normal_qty'] if 'weld_normal_qty' in vals else analytic_account.weld_normal_qty
        weld_ot_qty = vals['weld_ot_qty'] if 'weld_ot_qty' in vals else analytic_account.weld_ot_qty
        int_normal_qty = vals['int_normal_qty'] if 'int_normal_qty' in vals else analytic_account.int_normal_qty
        int_ot_qty = vals['int_ot_qty'] if 'int_ot_qty' in vals else analytic_account.int_ot_qty
        desg_normal_qty = vals['desg_normal_qty'] if 'desg_normal_qty' in vals else analytic_account.desg_normal_qty
        desg_ot_qty = vals['desg_ot_qty'] if 'desg_ot_qty' in vals else analytic_account.desg_ot_qty
        dept1_normal_qty = vals['dept1_normal_qty'] if 'dept1_normal_qty' in vals else analytic_account.dept1_normal_qty
        dept1_ot_qty = vals['dept1_ot_qty'] if 'dept1_ot_qty' in vals else analytic_account.dept1_ot_qty
        dept2_normal_qty = vals['dept2_normal_qty'] if 'dept2_normal_qty' in vals else analytic_account.dept2_normal_qty
        dept2_ot_qty = vals['dept2_ot_qty'] if 'dept2_ot_qty' in vals else analytic_account.dept2_ot_qty
        dept3_normal_qty = vals['dept3_normal_qty'] if 'dept3_normal_qty' in vals else analytic_account.dept3_normal_qty
        dept3_ot_qty = vals['dept3_ot_qty'] if 'dept3_ot_qty' in vals else analytic_account.dept3_ot_qty
        
        billing_type = vals['billing_type'] if 'billing_type' in vals else analytic_account.billing_type        
        
        if billing_type == 'bill':
            # 1st condition estimated hour(s) input must be greater than actual hour(s)
            self.get_error_write_cond1(cr,uid,ids, sy_normal_qty, analytic_account.sy_actual_normal_hours, 'normal', 'Shipyard')
            self.get_error_write_cond1(cr,uid,ids, sy_ot_qty, analytic_account.sy_actual_ot_hours, 'OT', 'Shipyard') 
            self.get_error_write_cond1(cr,uid,ids, mech_normal_qty, analytic_account.mech_actual_normal_hours, 'normal', 'Mechanical')
            self.get_error_write_cond1(cr,uid,ids, mech_ot_qty, analytic_account.mech_actual_ot_hours, 'OT', 'Mechanical') 
            self.get_error_write_cond1(cr,uid,ids, elec_normal_qty, analytic_account.elec_actual_normal_hours, 'normal', 'Electrical')
            self.get_error_write_cond1(cr,uid,ids, elec_ot_qty, analytic_account.elec_actual_ot_hours, 'OT', 'Electrical')
            self.get_error_write_cond1(cr,uid,ids, weld_normal_qty, analytic_account.weld_actual_normal_hours, 'normal', 'Welding & Fabrication')
            self.get_error_write_cond1(cr,uid,ids, weld_ot_qty, analytic_account.weld_actual_ot_hours, 'OT', 'Welding & Fabrication')
            self.get_error_write_cond1(cr,uid,ids, int_normal_qty, analytic_account.int_actual_normal_hours, 'normal', 'Interior')
            self.get_error_write_cond1(cr,uid,ids, int_ot_qty, analytic_account.int_actual_ot_hours, 'OT', 'Interior')
            self.get_error_write_cond1(cr,uid,ids, desg_normal_qty, analytic_account.desg_actual_normal_hours, 'normal', 'Design')
            self.get_error_write_cond1(cr,uid,ids, desg_ot_qty, analytic_account.desg_actual_ot_hours, 'OT', 'Design')
            self.get_error_write_cond1(cr,uid,ids, dept1_normal_qty, analytic_account.dept1_actual_normal_hours, 'normal', 'Other Dept1')
            self.get_error_write_cond1(cr,uid,ids, dept1_ot_qty, analytic_account.dept1_actual_ot_hours, 'OT', 'Other Dept1')
            self.get_error_write_cond1(cr,uid,ids, dept2_normal_qty, analytic_account.dept2_actual_normal_hours, 'normal', 'Other Dept2')
            self.get_error_write_cond1(cr,uid,ids, dept2_ot_qty, analytic_account.dept2_actual_ot_hours, 'OT', 'Other Dept2')
            self.get_error_write_cond1(cr,uid,ids, dept3_normal_qty, analytic_account.dept3_actual_normal_hours, 'normal', 'Other Dept3')
            self.get_error_write_cond1(cr,uid,ids, dept3_ot_qty, analytic_account.dept3_actual_ot_hours, 'OT', 'Other Dept3')
            
            # 2nd condition invoices hour(s) input must not be greater than actual hour(s)
            self.get_error_write_cond2(cr,uid,ids, analytic_account.sy_normal_invoice_qty, analytic_account.sy_actual_normal_hours, 'normal', 'Shipyard')
            self.get_error_write_cond2(cr,uid,ids, analytic_account.sy_ot_invoice_qty, analytic_account.sy_actual_ot_hours, 'OT', 'Shipyard')
            self.get_error_write_cond2(cr,uid,ids, analytic_account.mech_normal_invoice_qty, analytic_account.mech_actual_normal_hours, 'normal', 'Mechanical')
            self.get_error_write_cond2(cr,uid,ids, analytic_account.mech_ot_invoice_qty, analytic_account.mech_actual_ot_hours, 'OT', 'Mechanical')
            self.get_error_write_cond2(cr,uid,ids, analytic_account.elec_normal_invoice_qty, analytic_account.elec_actual_normal_hours, 'normal', 'Electrical')
            self.get_error_write_cond2(cr,uid,ids, analytic_account.elec_ot_invoice_qty, analytic_account.elec_actual_ot_hours, 'OT', 'Electrical')
            self.get_error_write_cond2(cr,uid,ids, analytic_account.weld_normal_invoice_qty, analytic_account.weld_actual_normal_hours, 'normal', 'Welding & Fabrication')
            self.get_error_write_cond2(cr,uid,ids, analytic_account.weld_ot_invoice_qty, analytic_account.weld_actual_ot_hours, 'OT', 'Welding & Fabrication') 
            self.get_error_write_cond2(cr,uid,ids, analytic_account.int_normal_invoice_qty, analytic_account.int_actual_normal_hours, 'normal', 'Interior')
            self.get_error_write_cond2(cr,uid,ids, analytic_account.int_ot_invoice_qty, analytic_account.int_actual_ot_hours, 'OT', 'Interior')
            self.get_error_write_cond2(cr,uid,ids, analytic_account.desg_normal_invoice_qty, analytic_account.desg_actual_normal_hours, 'normal', 'Design')
            self.get_error_write_cond2(cr,uid,ids, analytic_account.desg_ot_invoice_qty, analytic_account.desg_actual_ot_hours, 'OT', 'Design')
            self.get_error_write_cond2(cr,uid,ids, analytic_account.dept1_normal_invoice_qty, analytic_account.dept1_actual_normal_hours, 'normal', 'Other Dept1')
            self.get_error_write_cond2(cr,uid,ids, analytic_account.dept1_ot_invoice_qty, analytic_account.dept1_actual_ot_hours, 'OT', 'Other Dept1')
            self.get_error_write_cond2(cr,uid,ids, analytic_account.dept2_normal_invoice_qty, analytic_account.dept2_actual_normal_hours, 'normal', 'Other Dept2')
            self.get_error_write_cond2(cr,uid,ids, analytic_account.dept2_ot_invoice_qty, analytic_account.dept2_actual_ot_hours, 'OT', 'Other Dept2')
            self.get_error_write_cond2(cr,uid,ids, analytic_account.dept3_normal_invoice_qty, analytic_account.dept3_actual_normal_hours, 'normal', 'Other Dept3')
            self.get_error_write_cond2(cr,uid,ids, analytic_account.dept3_ot_invoice_qty, analytic_account.dept3_actual_ot_hours, 'OT', 'Other Dept3')
            
            
        elif billing_type == 'unbill':
            # 3rd condition for non actual billing, estimated hour(s) input must be greater than invoices hour(s)
            self.get_error_write_cond3(cr,uid,ids, sy_normal_qty, analytic_account.sy_normal_invoice_qty, 'normal', 'Shipyard')
            self.get_error_write_cond3(cr,uid,ids, sy_ot_qty, analytic_account.sy_ot_invoice_qty, 'OT', 'Shipyard') 
            self.get_error_write_cond3(cr,uid,ids, mech_normal_qty, analytic_account.mech_normal_invoice_qty, 'normal', 'Mechanical')
            self.get_error_write_cond3(cr,uid,ids, mech_ot_qty, analytic_account.mech_ot_invoice_qty, 'OT', 'Mechanical') 
            self.get_error_write_cond3(cr,uid,ids, elec_normal_qty, analytic_account.elec_normal_invoice_qty, 'normal', 'Electrical')
            self.get_error_write_cond3(cr,uid,ids, elec_ot_qty, analytic_account.elec_ot_invoice_qty, 'OT', 'Electrical')
            self.get_error_write_cond3(cr,uid,ids, weld_normal_qty, analytic_account.weld_normal_invoice_qty, 'normal', 'Welding & Fabrication')
            self.get_error_write_cond3(cr,uid,ids, weld_ot_qty, analytic_account.weld_ot_invoice_qty, 'OT', 'Welding & Fabrication')
            self.get_error_write_cond3(cr,uid,ids, int_normal_qty, analytic_account.int_normal_invoice_qty, 'normal', 'Interior')
            self.get_error_write_cond3(cr,uid,ids, int_ot_qty, analytic_account.int_ot_invoice_qty, 'OT', 'Interior')
            self.get_error_write_cond3(cr,uid,ids, desg_normal_qty, analytic_account.desg_normal_invoice_qty, 'normal', 'Design')
            self.get_error_write_cond3(cr,uid,ids, desg_ot_qty, analytic_account.desg_ot_invoice_qty, 'OT', 'Design')
            self.get_error_write_cond3(cr,uid,ids, dept1_normal_qty, analytic_account.dept1_normal_invoice_qty, 'normal', 'Other Dept1')
            self.get_error_write_cond3(cr,uid,ids, dept1_ot_qty, analytic_account.dept1_ot_invoice_qty, 'OT', 'Other Dept1')
            self.get_error_write_cond3(cr,uid,ids, dept2_normal_qty, analytic_account.dept2_normal_invoice_qty, 'normal', 'Other Dept2')
            self.get_error_write_cond3(cr,uid,ids, dept2_ot_qty, analytic_account.dept2_ot_invoice_qty, 'OT', 'Other Dept2')
            self.get_error_write_cond3(cr,uid,ids, dept3_normal_qty, analytic_account.dept3_normal_invoice_qty, 'normal', 'Other Dept3')
            self.get_error_write_cond3(cr,uid,ids, dept3_ot_qty, analytic_account.dept3_ot_invoice_qty, 'OT', 'Other Dept3')
            
        self.get_error_write(cr,uid,ids,'shipyard_line_ids', vals, 'Shipyard')
        self.get_error_write(cr,uid,ids,'mechanical_line_ids', vals, 'Mechanical')
        self.get_error_write(cr,uid,ids,'electrical_line_ids', vals, 'Electrical')
        self.get_error_write(cr,uid,ids,'welding_line_ids', vals, 'Welding & Fabrication')
        self.get_error_write(cr,uid,ids,'interior_line_ids', vals, 'Interior')
        self.get_error_write(cr,uid,ids,'design_line_ids', vals, 'Design')      
        self.get_error_write(cr,uid,ids,'department1_line_ids', vals, 'Other Dept1')
        self.get_error_write(cr,uid,ids,'department2_line_ids', vals, 'Other Dept2')
        self.get_error_write(cr,uid,ids,'department3_line_ids', vals, 'Other Dept3')
        
        self.get_error_write_srvc(cr,uid,ids,'ship_service_line_ids', vals, 'Shipyard')
        self.get_error_write_srvc(cr,uid,ids,'mech_service_line_ids', vals, 'Mechanical')
        self.get_error_write_srvc(cr,uid,ids,'elec_service_line_ids', vals, 'Electrical')
        self.get_error_write_srvc(cr,uid,ids,'weld_service_line_ids', vals, 'Welding & Fabrication')
        self.get_error_write_srvc(cr,uid,ids,'int_service_line_ids', vals, 'Interior')
        self.get_error_write_srvc(cr,uid,ids,'desg_service_line_ids', vals, 'Design')
        self.get_error_write_srvc(cr,uid,ids,'dept1_service_line_ids', vals, 'Other Dept1')
        self.get_error_write_srvc(cr,uid,ids,'dept2_service_line_ids', vals, 'Other Dept2')
        self.get_error_write_srvc(cr,uid,ids,'dept3_service_line_ids', vals, 'Other Dept3')
        
        return super(account_analytic_account, self).write(cr, uid, ids, vals, context=context)

    def _calc_sy_normal_amount(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for analytic in self.browse(cr, uid, ids, context=context):
            amount = 0
            amount = analytic.sy_normal_qty * analytic.sy_normal_price
            
            result[analytic.id] = amount
        return result
    
    def _calc_sy_ot_amount(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for analytic in self.browse(cr, uid, ids, context=context):
            amount = 0
            amount = analytic.sy_ot_qty * analytic.sy_ot_price
            
            result[analytic.id] = amount
        return result
    
    def _calc_mech_normal_amount(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for analytic in self.browse(cr, uid, ids, context=context):
            amount = 0
            amount = analytic.mech_normal_qty * analytic.mech_normal_price
            
            result[analytic.id] = amount
        return result
    
    def _calc_mech_ot_amount(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for analytic in self.browse(cr, uid, ids, context=context):
            amount = 0
            amount = analytic.mech_ot_qty * analytic.mech_ot_price
            
            result[analytic.id] = amount
        return result
    
    def _calc_elec_normal_amount(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for analytic in self.browse(cr, uid, ids, context=context):
            amount = 0
            amount = analytic.elec_normal_qty * analytic.elec_normal_price
            
            result[analytic.id] = amount
        return result
    
    def _calc_elec_ot_amount(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for analytic in self.browse(cr, uid, ids, context=context):
            amount = 0
            amount = analytic.elec_ot_qty * analytic.elec_ot_price
            
            result[analytic.id] = amount
        return result
    
    def _calc_weld_normal_amount(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for analytic in self.browse(cr, uid, ids, context=context):
            amount = 0
            amount = analytic.weld_normal_qty * analytic.weld_normal_price
            
            result[analytic.id] = amount
        return result
    
    def _calc_weld_ot_amount(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for analytic in self.browse(cr, uid, ids, context=context):
            amount = 0
            amount = analytic.weld_ot_qty * analytic.weld_ot_price
            
            result[analytic.id] = amount
        return result
    
    def _calc_int_normal_amount(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for analytic in self.browse(cr, uid, ids, context=context):
            amount = 0
            amount = analytic.int_normal_qty * analytic.int_normal_price
            
            result[analytic.id] = amount
        return result
    
    def _calc_int_ot_amount(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for analytic in self.browse(cr, uid, ids, context=context):
            amount = 0
            amount = analytic.int_ot_qty * analytic.int_ot_price
            
            result[analytic.id] = amount
        return result
    
    def _calc_desg_normal_amount(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for analytic in self.browse(cr, uid, ids, context=context):
            amount = 0
            amount = analytic.desg_normal_qty * analytic.desg_normal_price
            
            result[analytic.id] = amount
        return result
    
    def _calc_desg_ot_amount(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for analytic in self.browse(cr, uid, ids, context=context):
            amount = 0
            amount = analytic.desg_ot_qty * analytic.desg_ot_price
            
            result[analytic.id] = amount
        return result
    
    def _calc_dept1_normal_amount(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for analytic in self.browse(cr, uid, ids, context=context):
            amount = 0
            amount = analytic.dept1_normal_qty * analytic.dept1_normal_price
            
            result[analytic.id] = amount
        return result
    
    def _calc_dept1_ot_amount(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for analytic in self.browse(cr, uid, ids, context=context):
            amount = 0
            amount = analytic.dept1_ot_qty * analytic.dept1_ot_price
            
            result[analytic.id] = amount
        return result
    
    def _calc_dept2_normal_amount(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for analytic in self.browse(cr, uid, ids, context=context):
            amount = 0
            amount = analytic.dept2_normal_qty * analytic.dept2_normal_price
            
            result[analytic.id] = amount
        return result
    
    def _calc_dept2_ot_amount(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for analytic in self.browse(cr, uid, ids, context=context):
            amount = 0
            amount = analytic.dept2_ot_qty * analytic.dept2_ot_price
            
            result[analytic.id] = amount
        return result
    
    def _calc_dept3_normal_amount(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for analytic in self.browse(cr, uid, ids, context=context):
            amount = 0
            amount = analytic.dept3_normal_qty * analytic.dept3_normal_price
            
            result[analytic.id] = amount
        return result
    
    def _calc_dept3_ot_amount(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for analytic in self.browse(cr, uid, ids, context=context):
            amount = 0
            amount = analytic.dept3_ot_qty * analytic.dept3_ot_price
            
            result[analytic.id] = amount
        return result
    
    def _calc_subtotal_amount(self, cr, uid, ids, field_name, arg, context=None):
        res = {}
        
        for analytic in self.browse(cr, uid, ids, context=context):
            amount_ship = amount_mech = amount_elec = amount_weld = amount_int = amount_desg = amount_dept1 = amount_dept2 = amount_dept3 = amount_subtotal = 0
            
            if analytic.ship_state == 'approved':
                amount_ship = analytic.sy_normal_amount + analytic.sy_ot_amount

                for ship_line in analytic.shipyard_line_ids :
                    amount_ship += ship_line.amount

                for ship_srvc_line in analytic.ship_service_line_ids :
                    amount_ship += ship_srvc_line.amount
                
            if analytic.mech_state == 'approved':
                amount_mech = analytic.mech_normal_amount + analytic.mech_ot_amount
                
                for mech_line in analytic.mechanical_line_ids :
                    amount_mech += mech_line.amount
                
                for mech_srvc_line in analytic.mech_service_line_ids :
                    amount_mech += mech_srvc_line.amount
             
            if analytic.elec_state == 'approved':
                amount_elec = analytic.elec_normal_amount + analytic.elec_ot_amount
                
                for elec_line in analytic.electrical_line_ids :
                    amount_elec += elec_line.amount
                
                for elec_srvc_line in analytic.elec_service_line_ids :
                    amount_elec += elec_srvc_line.amount
            
            if analytic.weld_state == 'approved':
                amount_weld = analytic.weld_normal_amount + analytic.weld_ot_amount
                
                for weld_line in analytic.welding_line_ids :
                    amount_weld += weld_line.amount
                
                for weld_srvc_line in analytic.weld_service_line_ids :
                    amount_weld += weld_srvc_line.amount
            
            if analytic.int_state == 'approved':
                amount_int = analytic.int_normal_amount + analytic.int_ot_amount
                
                for int_line in analytic.interior_line_ids :
                    amount_int += int_line.amount
                
                for int_srvc_line in analytic.int_service_line_ids :
                    amount_int += int_srvc_line.amount
            
            if analytic.desg_state == 'approved':
                amount_desg = analytic.desg_normal_amount + analytic.desg_ot_amount
                
                for desg_line in analytic.design_line_ids :
                    amount_desg += desg_line.amount
                
                for desg_srvc_line in analytic.desg_service_line_ids :
                    amount_desg += desg_srvc_line.amount
            
            if analytic.dept1_state == 'approved':
                amount_dept1 = analytic.dept1_normal_amount + analytic.dept1_ot_amount
                
                for dept1_line in analytic.department1_line_ids :
                    amount_dept1 += dept1_line.amount
                
                for dept1_srvc_line in analytic.dept1_service_line_ids :
                    amount_dept1 += dept1_srvc_line.amount
            
            if analytic.dept2_state == 'approved':
                amount_dept2 = analytic.dept2_normal_amount + analytic.dept2_ot_amount
                
                for dept2_line in analytic.department2_line_ids :
                    amount_dept2 += dept2_line.amount
                
                for dept2_srvc_line in analytic.dept2_service_line_ids :
                    amount_dept2 += dept2_srvc_line.amount
            
            if analytic.dept3_state == 'approved':
                amount_dept3 = analytic.dept3_normal_amount + analytic.dept3_ot_amount
                
                for dept3_line in analytic.department3_line_ids :
                    amount_dept3 += dept3_line.amount
                
                for dept3_srvc_line in analytic.dept3_service_line_ids :
                    amount_dept3 += dept3_srvc_line.amount
                        
            amount_subtotal = amount_ship + amount_mech + amount_elec + amount_weld + amount_int + amount_desg + amount_dept1 + amount_dept2 + amount_dept3

            res[analytic.id] = amount_subtotal

        return res
    
    def _calc_grandtotal_amount(self, cr, uid, ids, field_name, arg, context=None):
        res = {}
        
        for analytic in self.browse(cr, uid, ids, context=context):
            amount_ttl = 0
             
            amount_ttl = analytic.amount_untaxed

            res[analytic.id] = amount_ttl
            
        return res
    
    def _get_int_move_ids(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for record in self.browse(cr, uid, ids, context=context):
            inv_ids = self.pool.get('stock.picking').search(cr, uid, [('project_id2.analytic_account_id', '=', record.id),('state', '=', 'done')])
            if inv_ids:
                result[record.id] = [x.id for x in self.pool.get('stock.picking').browse(cr, uid, inv_ids, context=context)]
            else:
                result[record.id] = []

        return result
    
    def _get_reduction_ids(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for record in self.browse(cr, uid, ids, context=context):
            inv_ids = self.pool.get('stock.inventory').search(cr, uid, [('analytic_account_id', '=', record.id),('state', '=', 'done')])
            if inv_ids:
                result[record.id] = [x.id for x in self.pool.get('stock.inventory').browse(cr, uid, inv_ids, context=context)]
            else:
                result[record.id] = []

        return result
    
    def _get_invoice_ids(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for record in self.browse(cr, uid, ids, context=context):
            inv_ids = self.pool.get('account.invoice').search(cr, uid, [('analytic_contract_id', '=', record.id),('state', '!=', 'cancel')])
            if inv_ids:
                result[record.id] = [x.id for x in self.pool.get('account.invoice').browse(cr, uid, inv_ids, context=context)]
            else:
                result[record.id] = []

        return result
    
    def _calc_invoice_amount(self, cr, uid, ids, field_name, arg, context=None):
        res = {}
        
        for analytic in self.browse(cr, uid, ids, context=context):
            amount_ttl = 0
            
            for inv in analytic.invoice_ids:
                amount_ttl += inv.amount_total

            res[analytic.id] = amount_ttl
            
        return res
    
    def _calc_invoice_amount_home(self, cr, uid, ids, field_name, arg, context=None):
        res = {}
        aml_obj = self.pool.get('account.move.line')
        
        for analytic in self.browse(cr, uid, ids, context=context):
            aml_debit = aml_credit = aml_home_amt = amount_ttl_home = 0
            
            for inv in analytic.invoice_ids:
                if inv.move_id:
                    aml_ids = aml_obj.search(cr, uid, [('move_id', '=', inv.move_id.id), ('account_id.type', '=', 'receivable')])
                    
                    for aml_id in aml_ids:
                        aml_debit = aml_obj.browse(cr, uid, aml_id).debit or 0
                        aml_credit = aml_obj.browse(cr, uid, aml_id).credit or 0
                        aml_home_amt = aml_debit - aml_credit
                        amount_ttl_home += aml_home_amt
                        
            res[analytic.id] = amount_ttl_home
                
        return res
    
    def _calc_amount_cost_total(self, cr, uid, ids, field_name, arg, context=None):
        res = {}
        
        sm_obj = self.pool.get('stock.move')
        aml_obj = self.pool.get('account.move.line')
        
        for analytic in self.browse(cr, uid, ids, context=context):
            total_cost = material_cost = 0
            #Material Cost Calculation
            for material in analytic.reduction_ids :
                material_cost = 0
                if analytic.reduction_ids:
                    sm_ids = sm_obj.search(cr, uid, [('inventory_id', '=', material.id)])
                    
                    for sm in sm_obj.browse(cr, uid, sm_ids):
                        if sm.move_id:
                            aml_ids = aml_obj.search(cr, uid, [('move_id', '=', sm.move_id.id)])
                    
                            for aml_id in aml_ids:
                                aml_credit = aml_obj.browse(cr, uid, aml_id).credit or 0
                                material_cost += aml_credit
            #Labour Cost and Service Cost Calculation for each Department
            amount_ship = amount_mech = amount_elec = amount_weld = amount_int = amount_desg = amount_dept1 = amount_dept2 = amount_dept3 = 0
            if analytic.ship_state == 'approved':
                amount_ship = (analytic.sy_normal_invoice_qty * analytic.sy_normal_cost) + (analytic.sy_ot_invoice_qty * analytic.sy_ot_cost)
                
                for ship_srvc_line in analytic.ship_service_line_ids :
                    amount_ship += (ship_srvc_line.invoices_service_qty * ship_srvc_line.cost_price)
                    
            if analytic.mech_state == 'approved':
                amount_mech = (analytic.mech_normal_invoice_qty * analytic.mech_normal_cost) + (analytic.mech_ot_invoice_qty * analytic.mech_ot_cost)

                for mech_srvc_line in analytic.mech_service_line_ids :
                    amount_mech += (mech_srvc_line.invoices_service_qty * mech_srvc_line.cost_price)
             
            if analytic.elec_state == 'approved':
                amount_elec = (analytic.elec_normal_invoice_qty * analytic.elec_normal_cost) + (analytic.elec_ot_invoice_qty * analytic.elec_ot_cost)

                for elec_srvc_line in analytic.elec_service_line_ids :
                    amount_elec += (elec_srvc_line.invoices_service_qty * elec_srvc_line.cost_price)
            
            if analytic.weld_state == 'approved':
                amount_weld = (analytic.weld_normal_invoice_qty * analytic.weld_normal_cost) + (analytic.weld_ot_invoice_qty * analytic.weld_ot_cost)

                for weld_srvc_line in analytic.weld_service_line_ids :
                    amount_weld += (weld_srvc_line.invoices_service_qty * weld_srvc_line.cost_price)
            
            if analytic.int_state == 'approved':
                amount_int = (analytic.int_normal_invoice_qty * analytic.int_normal_cost) + (analytic.int_ot_invoice_qty * analytic.int_ot_cost)

                for int_srvc_line in analytic.int_service_line_ids :
                    amount_int += (int_srvc_line.invoices_service_qty * int_srvc_line.cost_price)
            
            if analytic.desg_state == 'approved':
                amount_desg = (analytic.desg_normal_invoice_qty * analytic.desg_normal_cost) + (analytic.desg_ot_invoice_qty * analytic.desg_ot_cost)

                for desg_srvc_line in analytic.desg_service_line_ids :
                    amount_desg += (desg_srvc_line.invoices_service_qty * desg_srvc_line.cost_price)
            
            if analytic.dept1_state == 'approved':
                amount_dept1 = (analytic.dept1_normal_invoice_qty * analytic.dept1_normal_cost) + (analytic.dept1_ot_invoice_qty * analytic.dept1_ot_cost)

                for dept1_srvc_line in analytic.dept1_service_line_ids :
                    amount_dept1 += (dept1_srvc_line.invoices_service_qty * dept1_srvc_line.cost_price)
            
            if analytic.dept2_state == 'approved':
                amount_dept2 = (analytic.dept2_normal_invoice_qty * analytic.dept2_normal_cost) + (analytic.dept2_ot_invoice_qty * analytic.dept2_ot_cost)

                for dept2_srvc_line in analytic.dept2_service_line_ids :
                    amount_dept2 += (dept2_srvc_line.invoices_service_qty * dept2_srvc_line.cost_price)
            
            if analytic.dept3_state == 'approved':
                amount_dept3 = (analytic.dept3_normal_invoice_qty * analytic.dept3_normal_cost) + (analytic.dept3_ot_invoice_qty * analytic.dept3_ot_cost)

                for dept3_srvc_line in analytic.dept3_service_line_ids :
                    amount_dept3 += (dept3_srvc_line.invoices_service_qty * dept3_srvc_line.cost_price)
                    
            total_cost = material_cost + amount_ship + amount_mech + amount_elec + amount_weld + amount_int + amount_desg + amount_dept1 + amount_dept2 + amount_dept3
            res[analytic.id] = total_cost
        
        return res
    
    _columns = {
        'int_move_ids': fields.function(_get_int_move_ids, type='many2many', relation='stock.picking', string='Internal Move History', readonly=True),
        'reduction_ids': fields.function(_get_reduction_ids, type='many2many', relation='stock.inventory', string='Adjustment Reduction History', readonly=True),
        'invoice_ids': fields.function(_get_invoice_ids, type='many2many', relation='account.invoice', string='Invoice History', readonly=True),
        'dept1_alias': fields.function(_get_dept1_alias, type='char', string='Dept1'),
        'dept2_alias': fields.function(_get_dept2_alias, type='char', string='Dept2'),
        'dept3_alias': fields.function(_get_dept3_alias, type='char', string='Dept3'),
        'amount_untaxed': fields.function(_calc_subtotal_amount, type='float', string='Sub Total'),
        'amount_total': fields.function(_calc_grandtotal_amount, type='float', string='Grand Total'),
        'inv_amount_total': fields.function(_calc_invoice_amount, type='float', string='Grand Total Invoice'),
        'inv_amount_home_total': fields.function(_calc_invoice_amount_home, type='float', string='Grand Total Invoice in Home'),
        'amount_cost_total': fields.function(_calc_amount_cost_total, type='float', string='Grand Total Cost'),
        'real_partner_id': fields.function(_get_real_partner, type='many2one', relation='res.partner', string='Partner'),
        'billing_type':fields.selection([('bill','Actual'),
                                 ('unbill','Non Actual'),
                                 ], 'Labour Billing Type'),
        #Shipyard
        'sy_normal_product_id': fields.many2one('product.product', 'Normal Product'),
        'sy_ot_product_id': fields.many2one('product.product', 'OT Product'),
        'sy_normal_qty': fields.float('Estimated Normal Hour(s)'),
        'sy_actual_normal_hours': fields.function(_hours_get, string='Actual Normal Hours Spent', multi='hours'),
        'sy_ot_qty': fields.float('Estimated OT Hour(s)'),
        'sy_actual_ot_hours': fields.function(_hours_get, string='Actual OT Hours Spent', multi='hours'),
        'sy_normal_price': fields.float('Normal Price/Hour',digits_compute= dp.get_precision('Product Price')),
        'sy_ot_price': fields.float('OT Price/Hour',digits_compute= dp.get_precision('Product Price')),
        'shipyard_line_ids':fields.one2many('analytic.quotation.line','analytic_id','Shipyard',
            domain=[('type','=','shipyard')], context={'default_type':'shipyard'}),
        'ship_state':fields.selection([('draft','Draft'),
                                 ('approved','Approved'),
                                 ], 'State'),
        'sy_normal_invoice_qty': fields.function(_inv_hours_get, string='Normal Invoices Hour(s)', multi='float'),
        'sy_ot_invoice_qty': fields.function(_inv_hours_get, string='OT Invoices Hour(s)', multi='float'),
        'sy_normal_amount': fields.function(_calc_sy_normal_amount, type='float', string='Shipyard Normal Amount'),
        'sy_ot_amount': fields.function(_calc_sy_ot_amount, type='float', string='Shipyard OT Amount'),
        'sy_normal_cost': fields.float('Normal Hour Cost in Home'),
        'sy_ot_cost': fields.float('OT Hour Cost in Home'),
        #Mechanical
        'mech_normal_product_id': fields.many2one('product.product', 'Normal Product'),
        'mech_ot_product_id': fields.many2one('product.product', 'OT Product'),
        'mech_normal_qty': fields.float('Estimated Normal Hour(s)'),
        'mech_actual_normal_hours': fields.function(_hours_get, string='Actual Normal Hours Spent', multi='hours'),
        'mech_ot_qty': fields.float('Estimated OT Hour(s)'),
        'mech_actual_ot_hours': fields.function(_hours_get, string='Actual OT Hours Spent', multi='hours'),
        'mech_normal_price': fields.float('Normal Price/Hour',digits_compute= dp.get_precision('Product Price')),
        'mech_ot_price': fields.float('OT Price/Hour',digits_compute= dp.get_precision('Product Price')),
        'mechanical_line_ids':fields.one2many('analytic.quotation.line','analytic_id','Mechanical',
            domain=[('type','=','mechanical')], context={'default_type':'mechanical'}),
        'mech_state':fields.selection([('draft','Draft'),
                                 ('approved','Approved'),
                                 ], 'State'),
        'mech_normal_invoice_qty': fields.function(_inv_hours_get, string='Normal Invoices Hour(s)', multi='float'),
        'mech_ot_invoice_qty': fields.function(_inv_hours_get, string='OT Invoices Hour(s)', multi='float'),
        'mech_normal_amount': fields.function(_calc_mech_normal_amount, type='float', string='Mechanical Normal Amount'),
        'mech_ot_amount': fields.function(_calc_mech_ot_amount, type='float', string='Mechanical OT Amount'),
        'mech_normal_cost': fields.float('Normal Hour Cost in Home'),
        'mech_ot_cost': fields.float('OT Hour Cost in Home'),
        #Electrical
        'elec_normal_product_id': fields.many2one('product.product', 'Normal Product'),
        'elec_ot_product_id': fields.many2one('product.product', 'OT Product'),
        'elec_normal_qty': fields.float('Estimated Normal Hour(s)'),
        'elec_actual_normal_hours': fields.function(_hours_get, string='Actual Normal Hours Spent', multi='hours'),
        'elec_ot_qty': fields.float('Estimated OT Hour(s)'),
        'elec_actual_ot_hours': fields.function(_hours_get, string='Actual OT Hours Spent', multi='hours'),
        'elec_normal_price': fields.float('Normal Price/Hour',digits_compute= dp.get_precision('Product Price')),
        'elec_ot_price': fields.float('OT Price/Hour',digits_compute= dp.get_precision('Product Price')),
        'electrical_line_ids':fields.one2many('analytic.quotation.line','analytic_id','Electrical',
            domain=[('type','=','electrical')], context={'default_type':'electrical'}),
        'elec_state':fields.selection([('draft','Draft'),
                                 ('approved','Approved'),
                                 ], 'State'),
        'elec_normal_invoice_qty': fields.function(_inv_hours_get, string='Normal Invoices Hour(s)', multi='float'),
        'elec_ot_invoice_qty': fields.function(_inv_hours_get, string='OT Invoices Hour(s)', multi='float'),
        'elec_normal_amount': fields.function(_calc_elec_normal_amount, type='float', string='Electrical Normal Amount'),
        'elec_ot_amount': fields.function(_calc_elec_ot_amount, type='float', string='Electrical OT Amount'),
        'elec_normal_cost': fields.float('Normal Hour Cost in Home'),
        'elec_ot_cost': fields.float('OT Hour Cost in Home'),
        #Welding & Fabrication
        'weld_normal_product_id': fields.many2one('product.product', 'Normal Product'),
        'weld_ot_product_id': fields.many2one('product.product', 'OT Product'),
        'weld_normal_qty': fields.float('Estimated Normal Hour(s)'),
        'weld_actual_normal_hours': fields.function(_hours_get, string='Actual Normal Hours Spent', multi='hours'),
        'weld_ot_qty': fields.float('Estimated OT Hour(s)'),
        'weld_actual_ot_hours': fields.function(_hours_get, string='Actual OT Hours Spent', multi='hours'),
        'weld_normal_price': fields.float('Normal Price/Hour',digits_compute= dp.get_precision('Product Price')),
        'weld_ot_price': fields.float('OT Price/Hour',digits_compute= dp.get_precision('Product Price')),
        'welding_line_ids':fields.one2many('analytic.quotation.line','analytic_id','Welding & Fabrication',
            domain=[('type','=','welding_fabrication')], context={'default_type':'welding_fabrication'}),
        'weld_state':fields.selection([('draft','Draft'),
                                 ('approved','Approved'),
                                 ], 'State'),
        'weld_normal_invoice_qty': fields.function(_inv_hours_get, string='Normal Invoices Hour(s)', multi='float'),
        'weld_ot_invoice_qty': fields.function(_inv_hours_get, string='OT Invoices Hour(s)', multi='float'),
        'weld_normal_amount': fields.function(_calc_weld_normal_amount, type='float', string='Welding Normal Amount'),
        'weld_ot_amount': fields.function(_calc_weld_ot_amount, type='float', string='Welding OT Amount'),
        'weld_normal_cost': fields.float('Normal Hour Cost in Home'),
        'weld_ot_cost': fields.float('OT Hour Cost in Home'),
        #Interior
        'int_normal_product_id': fields.many2one('product.product', 'Normal Product'),
        'int_ot_product_id': fields.many2one('product.product', 'OT Product'),
        'int_normal_qty': fields.float('Estimated Normal Hour(s)'),
        'int_actual_normal_hours': fields.function(_hours_get, string='Actual Normal Hours Spent', multi='hours'),
        'int_ot_qty': fields.float('Estimated OT Hour(s)'),
        'int_actual_ot_hours': fields.function(_hours_get, string='Actual OT Hours Spent', multi='hours'),
        'int_normal_price': fields.float('Normal Price/Hour',digits_compute= dp.get_precision('Product Price')),
        'int_ot_price': fields.float('OT Price/Hour',digits_compute= dp.get_precision('Product Price')),
        'interior_line_ids':fields.one2many('analytic.quotation.line','analytic_id','Interior',
            domain=[('type','=','interior')], context={'default_type':'interior'}),
        'int_state':fields.selection([('draft','Draft'),
                                 ('approved','Approved'),
                                 ], 'State'),
        'int_normal_invoice_qty': fields.function(_inv_hours_get, string='Normal Invoices Hour(s)', multi='float'),
        'int_ot_invoice_qty': fields.function(_inv_hours_get, string='OT Invoices Hour(s)', multi='float'),
        'int_normal_amount': fields.function(_calc_int_normal_amount, type='float', string='Interior Normal Amount'),
        'int_ot_amount': fields.function(_calc_int_ot_amount, type='float', string='Interior OT Amount'),
        'int_normal_cost': fields.float('Normal Hour Cost in Home'),
        'int_ot_cost': fields.float('OT Hour Cost in Home'),
        #Design
        'desg_normal_product_id': fields.many2one('product.product', 'Normal Product'),
        'desg_ot_product_id': fields.many2one('product.product', 'OT Product'),
        'desg_normal_qty': fields.float('Estimated Normal Hour(s)'),
        'desg_actual_normal_hours': fields.function(_hours_get, string='Actual Normal Hours Spent', multi='hours'),
        'desg_ot_qty': fields.float('Estimated OT Hour(s)'),
        'desg_actual_ot_hours': fields.function(_hours_get, string='Actual OT Hours Spent', multi='hours'),
        'desg_normal_price': fields.float('Normal Price/Hour',digits_compute= dp.get_precision('Product Price')),
        'desg_ot_price': fields.float('OT Price/Hour',digits_compute= dp.get_precision('Product Price')),
        'design_line_ids':fields.one2many('analytic.quotation.line','analytic_id','Design',
            domain=[('type','=','design')], context={'default_type':'design'}),
        'desg_state':fields.selection([('draft','Draft'),
                                 ('approved','Approved'),
                                 ], 'State'),
        'desg_normal_invoice_qty': fields.function(_inv_hours_get, string='Normal Invoices Hour(s)', multi='float'),
        'desg_ot_invoice_qty': fields.function(_inv_hours_get, string='OT Invoices Hour(s)', multi='float'),
        'desg_normal_amount': fields.function(_calc_desg_normal_amount, type='float', string='Design Normal Amount'),
        'desg_ot_amount': fields.function(_calc_desg_ot_amount, type='float', string='Design OT Amount'),             
        'desg_normal_cost': fields.float('Normal Hour Cost in Home'),
        'desg_ot_cost': fields.float('OT Hour Cost in Home'),
        #Other dept 1 
        'dept1_normal_product_id': fields.many2one('product.product', 'Normal Product'),
        'dept1_ot_product_id': fields.many2one('product.product', 'OT Product'),
        'dept1_normal_qty': fields.float('Estimated Normal Hour(s)'),
        'dept1_actual_normal_hours': fields.function(_hours_get, string='Actual Normal Hours Spent', multi='hours'),
        'dept1_ot_qty': fields.float('Estimated OT Hour(s)'),
        'dept1_actual_ot_hours': fields.function(_hours_get, string='Actual OT Hours Spent', multi='hours'),
        'dept1_normal_price': fields.float('Normal Price/Hour',digits_compute= dp.get_precision('Product Price')),
        'dept1_ot_price': fields.float('OT Price/Hour',digits_compute= dp.get_precision('Product Price')),
        'department1_line_ids':fields.one2many('analytic.quotation.line','analytic_id','Department1',
            domain=[('type','=','other_dept1')], context={'default_type':'other_dept1'}),
        'dept1_state':fields.selection([('draft','Draft'),
                                 ('approved','Approved'),
                                 ], 'State'),
        'dept1_normal_invoice_qty': fields.function(_inv_hours_get, string='Normal Invoices Hour(s)', multi='float'),
        'dept1_ot_invoice_qty': fields.function(_inv_hours_get, string='OT Invoices Hour(s)', multi='float'),
        'dept1_normal_amount': fields.function(_calc_dept1_normal_amount, type='float', string='Department1 Normal Amount'),
        'dept1_ot_amount': fields.function(_calc_dept1_ot_amount, type='float', string='Department1 OT Amount'),
        'dept1_normal_cost': fields.float('Normal Hour Cost in Home'),
        'dept1_ot_cost': fields.float('OT Hour Cost in Home'),
        #Other dept 2
        'dept2_normal_product_id': fields.many2one('product.product', 'Normal Product'),
        'dept2_ot_product_id': fields.many2one('product.product', 'OT Product'),
        'dept2_normal_qty': fields.float('Estimated Normal Hour(s)'),
        'dept2_actual_normal_hours': fields.function(_hours_get, string='Actual Normal Hours Spent', multi='hours'),
        'dept2_ot_qty': fields.float('Estimated OT Hour(s)'),
        'dept2_actual_ot_hours': fields.function(_hours_get, string='Actual OT Hours Spent', multi='hours'),
        'dept2_normal_price': fields.float('Normal Price/Hour',digits_compute= dp.get_precision('Product Price')),
        'dept2_ot_price': fields.float('OT Price/Hour',digits_compute= dp.get_precision('Product Price')),
        'department2_line_ids':fields.one2many('analytic.quotation.line','analytic_id','Department2',
            domain=[('type','=','other_dept2')], context={'default_type':'other_dept2'}),
        'dept2_state':fields.selection([('draft','Draft'),
                                 ('approved','Approved'),
                                 ], 'State'),
        'dept2_normal_invoice_qty': fields.function(_inv_hours_get, string='Normal Invoices Hour(s)', multi='float'),
        'dept2_ot_invoice_qty': fields.function(_inv_hours_get, string='OT Invoices Hour(s)', multi='float'),
        'dept2_normal_amount': fields.function(_calc_dept2_normal_amount, type='float', string='Department2 Normal Amount'),
        'dept2_ot_amount': fields.function(_calc_dept2_ot_amount, type='float', string='Department2 OT Amount'),
        'dept2_normal_cost': fields.float('Normal Hour Cost in Home'),
        'dept2_ot_cost': fields.float('OT Hour Cost in Home'),
        #Other dept 3
        'dept3_normal_product_id': fields.many2one('product.product', 'Normal Product'),
        'dept3_ot_product_id': fields.many2one('product.product', 'OT Product'),
        'dept3_normal_qty': fields.float('Estimated Normal Hour(s)'),
        'dept3_actual_normal_hours': fields.function(_hours_get, string='Actual Normal Hours Spent', multi='hours'),
        'dept3_ot_qty': fields.float('Estimated OT Hour(s)'),
        'dept3_actual_ot_hours': fields.function(_hours_get, string='Actual OT Hours Spent', multi='hours'),
        'dept3_normal_price': fields.float('Normal Price/Hour',digits_compute= dp.get_precision('Product Price')),
        'dept3_ot_price': fields.float('OT Price/Hour',digits_compute= dp.get_precision('Product Price')),
        'department3_line_ids':fields.one2many('analytic.quotation.line','analytic_id','Department3',
            domain=[('type','=','other_dept3')], context={'default_type':'other_dept3'}),
        'dept3_state':fields.selection([('draft','Draft'),
                                 ('approved','Approved'),
                                 ], 'State'),
        'dept3_normal_invoice_qty': fields.function(_inv_hours_get, string='Normal Invoices Hour(s)', multi='float'),
        'dept3_ot_invoice_qty': fields.function(_inv_hours_get, string='OT Invoices Hour(s)', multi='float'),
        'dept3_normal_amount': fields.function(_calc_dept3_normal_amount, type='float', string='Department3 Normal Amount'),
        'dept3_ot_amount': fields.function(_calc_dept3_ot_amount, type='float', string='Department3 OT Amount'),
        'dept3_normal_cost': fields.float('Normal Hour Cost in Home'),
        'dept3_ot_cost': fields.float('OT Hour Cost in Home'),
        
        'ship_service_line_ids':fields.one2many('analytic.service.quotation.line','analytic_service_id','Shipyard',
            domain=[('type','=','shipyard')], context={'default_type':'shipyard'}),
        'mech_service_line_ids':fields.one2many('analytic.service.quotation.line','analytic_service_id','Mechanical',
            domain=[('type','=','mechanical')], context={'default_type':'mechanical'}),
        'elec_service_line_ids':fields.one2many('analytic.service.quotation.line','analytic_service_id','Electrical',
            domain=[('type','=','electrical')], context={'default_type':'electrical'}),
        'weld_service_line_ids':fields.one2many('analytic.service.quotation.line','analytic_service_id','Welding & Fabrication',
            domain=[('type','=','welding_fabrication')], context={'default_type':'welding_fabrication'}),
        'int_service_line_ids':fields.one2many('analytic.service.quotation.line','analytic_service_id','Interior',
            domain=[('type','=','interior')], context={'default_type':'interior'}),
        'desg_service_line_ids':fields.one2many('analytic.service.quotation.line','analytic_service_id','Design',
            domain=[('type','=','design')], context={'default_type':'design'}),
        'dept1_service_line_ids':fields.one2many('analytic.service.quotation.line','analytic_service_id','Other Department1',
            domain=[('type','=','other_dept1')], context={'default_type':'other_dept1'}),
        'dept2_service_line_ids':fields.one2many('analytic.service.quotation.line','analytic_service_id','Other Department2',
            domain=[('type','=','other_dept2')], context={'default_type':'other_dept2'}),
        'dept3_service_line_ids':fields.one2many('analytic.service.quotation.line','analytic_service_id','Other Department3',
            domain=[('type','=','other_dept3')], context={'default_type':'other_dept3'}),
    }

    _defaults = {
        'ship_state'  : 'draft',
        'mech_state'  : 'draft',
        'elec_state'  : 'draft',
        'weld_state'  : 'draft',
        'int_state'   : 'draft',
        'desg_state'  : 'draft',
        'dept1_state' : 'draft',
        'dept2_state' : 'draft',
        'dept3_state' : 'draft',
    }

    def onchange_product_id_normal(self, cr, uid, ids, product_id, normal_price, normal_cost, context=None):
        if context is None:
            context = {}
        res = {}
        if not product_id:
            return res
         
        product = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
        res['value'] = {normal_price: product.list_price, normal_cost: product.srvc_cost_price}
        return res
    
    def onchange_product_id_ot(self, cr, uid, ids, product_id, ot_price, ot_cost, context=None):
        if context is None:
            context = {}
        res = {}
        if not product_id:
            return res
        product = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
        res['value'] = {ot_price: product.list_price, ot_cost: product.srvc_cost_price}
        return res

    def action_app_ship(self, cr, uid, ids, context=None):
        if context is None:
            context = {}
        if context.get('type', '') == 'ship_state':
            return self.write(cr, uid, ids, {'ship_state': 'approved'}, context=context)
        if context.get('type', '') == 'mech_state':
            return self.write(cr, uid, ids, {'mech_state': 'approved'}, context=context)
        if context.get('type', '') == 'elec_state':
            return self.write(cr, uid, ids, {'elec_state': 'approved'}, context=context)
        if context.get('type', '') == 'weld_state':
            return self.write(cr, uid, ids, {'weld_state': 'approved'}, context=context)
        if context.get('type', '') == 'int_state':
            return self.write(cr, uid, ids, {'int_state': 'approved'}, context=context)
        if context.get('type', '') == 'desg_state':
            return self.write(cr, uid, ids, {'desg_state': 'approved'}, context=context)
        if context.get('type', '') == 'dept1_state':
            return self.write(cr, uid, ids, {'dept1_state': 'approved'}, context=context)
        if context.get('type', '') == 'dept2_state':
            return self.write(cr, uid, ids, {'dept2_state': 'approved'}, context=context)
        if context.get('type', '') == 'dept3_state':
            return self.write(cr, uid, ids, {'dept3_state': 'approved'}, context=context)
    
    def action_set_draft_ship(self, cr, uid, ids, context=None):
        if context is None:
            context = {}
        if context.get('type', '') == 'ship_state':
            return self.write(cr, uid, ids, {'ship_state': 'draft'}, context=context)
        if context.get('type', '') == 'mech_state':
            return self.write(cr, uid, ids, {'mech_state': 'draft'}, context=context)
        if context.get('type', '') == 'elec_state':
            return self.write(cr, uid, ids, {'elec_state': 'draft'}, context=context)
        if context.get('type', '') == 'weld_state':
            return self.write(cr, uid, ids, {'weld_state': 'draft'}, context=context)
        if context.get('type', '') == 'int_state':
            return self.write(cr, uid, ids, {'int_state': 'draft'}, context=context)
        if context.get('type', '') == 'desg_state':
            return self.write(cr, uid, ids, {'desg_state': 'draft'}, context=context)
        if context.get('type', '') == 'dept1_state':
            return self.write(cr, uid, ids, {'dept1_state': 'draft'}, context=context)
        if context.get('type', '') == 'dept2_state':
            return self.write(cr, uid, ids, {'dept2_state': 'draft'}, context=context)
        if context.get('type', '') == 'dept3_state':
            return self.write(cr, uid, ids, {'dept3_state': 'draft'}, context=context)


    def _analytic_invoice_create_line(self, cr, uid, ids, journal_id, analy_inv_lines, inv_type, context=None):
        invoice_obj = self.pool.get('account.invoice')
        invoice_line_obj = self.pool.get('account.invoice.line')

        invoices = {}
        for analytic in self.browse(cr, uid, ids, context=context):
            company_id = analytic.company_id.id
            origin = analytic.code or False
            partner = analytic.partner_id
            user_id = analytic.user_id.id
            currency_id = analytic.currency_id.id

            key = (origin, partner, currency_id, company_id, user_id, analytic.id)
            invoice_vals = self._get_analytic_invoice_vals(cr, uid, key, inv_type, journal_id, analytic, context=context)
            invoice_id = invoice_obj.create(cr, uid, invoice_vals, context=context)
            
            for inv_line in analy_inv_lines:
                inv_line['invoice_id'] = invoice_id
                invoice_line_obj.create(cr, uid, inv_line, context=context)
            workflow.trg_validate(uid, 'account.invoice', invoice_id, 'invoice_open', cr)
        return invoice_id
    
    def _get_analytic_invoice_vals(self, cr, uid, key, inv_type, journal_id, analytic, context=None):
        if context is None:
            context = {}
        origin, partner, currency_id, company_id, user_id, analytic_id = key
        if inv_type in ('out_invoice', 'out_refund'):
            account_id = partner.property_account_receivable.id
            payment_term = partner.property_payment_term.id or False
        else:
            account_id = partner.property_account_payable.id
            payment_term = partner.property_supplier_payment_term.id or False
        return {
            'origin': origin,
            'date_invoice': context.get('date_inv', False),
            'user_id': user_id,
            'partner_id': partner.id,
            'account_id': account_id,
            'payment_term': payment_term,
            'type': inv_type,
            'fiscal_position': partner.property_account_position.id,
            'company_id': company_id,
            'currency_id': currency_id,
            'journal_id': journal_id,
            'change_rate': context.get('exrate', False),
            'analytic_contract_id': analytic_id,
        }
   
class analytic_quotation_line(osv.osv):
    _name = 'analytic.quotation.line'
    _description = 'Analytic Quotation Line'

    def _calc_qty(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        product_uom_obj = self.pool.get('product.uom')
        for analytic_line in self.browse(cr, uid, ids, context=context):
            default_uom = analytic_line.product_id.uom_id and analytic_line.product_id.uom_id.id
            q = product_uom_obj._compute_qty(cr, uid, analytic_line.product_uom and analytic_line.product_uom.id, \
                                             analytic_line.product_qty, default_uom)
            result[analytic_line.id] = q
        return result

    def _calc_generate_qty(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        product_uom_obj = self.pool.get('product.uom')
        spt_obj = self.pool.get('stock.picking.type')
        sm_obj = self.pool.get('stock.move')
        analy_quo_obj = self.pool.get('analytic.quotation.line')
        
        for analytic_line in self.browse(cr, uid, ids, context=context):
            spt_ids = spt_obj.search(cr, uid, [('code', '=', 'internal'),('active', '=', True)], context=context)
            spt = spt_obj.browse(cr, uid, spt_ids[0], context=context)

            analy_id = analy_quo_obj.browse(cr, uid, analytic_line.id).analytic_id.id or False
            sm_qty = 0
            if analy_id:
                cr.execute("SELECT sm.id from stock_move sm " + \
                        "left join stock_picking sp on sm.picking_id = sp.id " + \
                        "left join project_project pp on sp.project_id2 = pp.id " + \
                        "left join stock_picking_type spt on spt.id = sp.picking_type_id " + \
                         "where sp.state = 'done' and sm.picking_id is not null and spt.code = 'internal' and sm.product_id = %s and sp.department = %s and pp.analytic_account_id = %s", \
                        (analytic_line.product_id.id, analytic_line.type, analy_id))

                sm_ids = cr.dictfetchall()
                if sm_ids:
                    for r in sm_ids:
                        sm = sm_obj.browse(cr, uid, r['id'], context=context)
                        default_uom = sm.product_id.uom_id and sm.product_id.uom_id.id
                        q = product_uom_obj._compute_qty(cr, uid, sm.product_uom and sm.product_uom.id, \
                                                 sm.product_uom_qty, default_uom)
                        if (sm.location_id.id == spt.default_location_src_id.id) and  (sm.location_dest_id.id == spt.default_location_dest_id.id):
                            sm_qty += q
                        if (sm.location_id.id == spt.default_location_dest_id.id) and  (sm.location_dest_id.id == spt.default_location_src_id.id):
                            sm_qty -= q
            result[analytic_line.id] = sm_qty

        return result

    def _calc_invoices_qty(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        product_uom_obj = self.pool.get('product.uom')
        
        for analytic_line in self.browse(cr, uid, ids, context=context):
            sm_qty = 0
            for il in analytic_line.invoice_line_ids:
                if il.invoice_id.state <> 'cancel':
                    sm_qty += product_uom_obj._compute_qty(cr, uid, il.uos_id.id, il.quantity, il.product_id.uom_id.id)
            result[analytic_line.id] = sm_qty
        return result
    
    def _calc_inv_amount(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for analytic_line in self.browse(cr, uid, ids, context=context):
            amount = 0
            amount = analytic_line.product_qty * analytic_line.unit_price
            
            result[analytic_line.id] = amount
        return result
    
    _columns = {
        'invoice_line_ids':fields.one2many('account.invoice.line','analytic_line_id','Invoices'),
        'analytic_id': fields.many2one('account.analytic.account', 'Analytic Account', required=True, ondelete='cascade', select=True),
        'product_id': fields.many2one('product.product', 'Product'),
        'product_qty': fields.float('Qty'),
        'unit_price': fields.float('Unit Price',digits_compute= dp.get_precision('Product Price')),
        'product_uom': fields.many2one('product.uom', 'UoM', required=True),
        'type':fields.selection([('shipyard','Shipyard'),
                                 ('mechanical','Mechanical'),
                                 ('electrical','Electrical'),
                                 ('welding_fabrication','Welding & Fabrication'),
                                 ('interior','Interior'),
                                 ('design','Design'),
                                 ('other_dept1','Other Dept1'),
                                 ('other_dept2','Other Dept2'),
                                 ('other_dept3','Other Dept3')
                                 ], 'Type'),
        'real_qty': fields.function(_calc_qty, type='float', string='Real Qty'),
        'process_qty': fields.function(_calc_generate_qty, type='float', string='Int Move Qty'),
        'invoices_qty': fields.function(_calc_invoices_qty, type='float', string='Inv Qty'),
        'amount': fields.function(_calc_inv_amount, type='float', string='Amount'),
    }
    
    def onchange_product_id(self, cr, uid, ids, product_id, context=None):
        if context is None:
            context = {}
        res = {}
        if not product_id:
            return res
        product = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
        res['domain'] = {'product_uom': [('category_id', '=', product.uom_id.category_id.id)]}
        res['value'] = {'unit_price': product.list_price, 'product_uom': product.uom_id.id}
        return res

    def _get_uom_id(self, cr, uid, *args):
        try:
            proxy = self.pool.get('ir.model.data')
            result = proxy.get_object_reference(cr, uid, 'product', 'product_uom_unit')
            return result[1]
        except Exception, ex:
            return False

    _defaults = {
        'product_uom' : _get_uom_id,
        'product_qty': 1,
    }
    
class analytic_service_quotation_line(osv.osv):
    _name = 'analytic.service.quotation.line'
    _description = 'Analytic Service Quotation Line'
    
    def _calc_srvc_amount(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        for analytic_line in self.browse(cr, uid, ids, context=context):
            amount = 0
            amount = analytic_line.product_qty * analytic_line.unit_price
            
            result[analytic_line.id] = amount
        return result
    
    def _calc_srvc_invoices_qty(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        product_uom_obj = self.pool.get('product.uom')

        for analytic_line in self.browse(cr, uid, ids, context=context):
            sm_qty = 0
            for il in analytic_line.invoice_service_line_ids:
                if il.invoice_id.state <> 'cancel':
                    sm_qty += product_uom_obj._compute_qty(cr, uid, il.uos_id.id, il.quantity, il.product_id.uom_id.id)
            result[analytic_line.id] = sm_qty
        return result
    
    _columns = {
    'invoice_service_line_ids':fields.one2many('account.invoice.line','analytic_service_line_id','Service Invoices'),
    'analytic_service_id': fields.many2one('account.analytic.account', 'Analytic Account Service', required=True, ondelete='cascade', select=True),
    'product_id': fields.many2one('product.product', 'Product'),
    'product_qty': fields.float('Quantity'),
    'unit_price': fields.float('Unit Price',digits_compute= dp.get_precision('Product Price')),
    'cost_price': fields.float('Cost Price in Home',digits_compute= dp.get_precision('Product Price')),
    'type':fields.selection([('shipyard','Shipyard'),
                             ('mechanical','Mechanical'),
                             ('electrical','Electrical'),
                             ('welding_fabrication','Welding & Fabrication'),
                             ('interior','Interior'),
                             ('design','Design'),
                             ('other_dept1','Other Dept1'),
                             ('other_dept2','Other Dept2'),
                             ('other_dept3','Other Dept3')
                             ], 'Type'),
    'invoices_service_qty': fields.function(_calc_srvc_invoices_qty, type='float', string='Invoices Quantity'),
    'amount': fields.function(_calc_srvc_amount, type='float', string='Amount'),
    }
    
    def onchange_product_id(self, cr, uid, ids, product_id, context=None):
        if context is None:
            context = {}
        res = {}
        if not product_id:
            return res
        product = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
        res['value'] = {'unit_price': product.list_price, 'cost_price': product.srvc_cost_price}
        return res
    
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
